home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / A86V402.ZIP / TCOLS.8 < prev    next >
Text File  |  1994-01-31  |  17KB  |  405 lines

  1. ;---------------
  2. ;   TCOLS
  3. ;---------------
  4.  
  5.   JMP TCOLS
  6.  
  7. DEFAULT MACRO
  8.   DEFT_#1 EQU #2
  9.   DB ' (default #2)',0D,0A
  10. #EM
  11.  
  12. DOC_MSG:
  13.  
  14. DB 0D,0A
  15. DB 'TCOLS V1.1  Copr.1994 Eric Isaacson, 416 E. Univ.St., BMG IN 47401',0D,0A
  16. DB '  Permission to use granted only to registered A86 users.',0D,0A,0D,0A
  17.  
  18.   DB 'TCOLS converts single-column input into paged, multi-column output.',0D,0A
  19.   DB 'Usage: TCOLS <in >out #1 #2 #3 #4 #5          , where',0D,0A
  20.   DB '  #1 is the number of major columns you want each page split into',0D,0A
  21.   DB '  #2 is the number of lines to skip between each page'
  22.   DEFAULT  SKIPCT,6
  23.   DB '  #3 is the number of chars per line the printer is now set to'
  24.   DEFAULT  PWIDTH,80
  25.   DB '  #4 is the number of lines per page the printer is now set to'
  26.   DEFAULT  LPAGE,66
  27.   DB '  #5 is which line within the first page the printer is now at'
  28.   DEFAULT  LSTART,0
  29.   DB          0D,0A
  30.  
  31. DB 'Examples:',0D,0A
  32. DB 'TCOLS <MYPROG.XRF >PRN 4 6 96 88',0D,0A
  33. DB '   sends the file MYPROG.XRF to the printer, split into 4 columns, where'
  34. DB          0D,0A
  35. DB '   the printer is set to 96 characters a line, 8 lines per inch.',0D,0A
  36. DB 'TCOLS <NARROW.LST 6 0 80 23 22 | MORE',0D,0A
  37. DB '   provides 6-column screen-paged output.',0D,0A
  38. DB 'NOTE for readability, TCOLS will convert underscores to hyphens when the'
  39. DB          0D,0A
  40. DB '   lines per page is greater than 80.',0D,0A
  41.  
  42. DOC_LEN EQU $-DOC_MSG
  43.  
  44. DATA SEGMENT
  45. BUF:
  46.          DB 04000 DUP (?)
  47. OUTBUF:
  48.          DB 02000 DUP (?)
  49. OUTBUF_LIM:
  50.          DB 0100 DUP (?)
  51.          DW ?          ; in case the line-overflow logic scans back
  52. SOURCE_BUF:
  53.          DB 04002 DUP (?)
  54.   WIDTH      DW ?   ; number of characters in an major output column
  55.   NCOLS      DB ?   ; number of major output columns on a page
  56.   LPAGE      DB ?   ; total number of lines on a page (including skipped)
  57.   PWIDTH     DW ?   ; total width in characters of a printed page
  58.   BUFEND     DW ?   ; pointer reached when a buffered page is complete
  59.   SKIPCT     DB ?   ; number of lines skipped between pages
  60.   LSTART     DB ?   ; number of first-page lines already output before program
  61.   THISPAGE   DB ?   ; number of printed lines on this page
  62. DATA ENDS
  63.  
  64. MAIN:
  65. TCOLS:
  66.   CALL SCAN_ARGS    ; scan the command arguments
  67.   CALL READ_SOURCE  ; read the first block of source text
  68.   JZ >L2        ; exit if there was no source text
  69. L1:            ; loop here for each page of output
  70.   CALL GATHER_PAGE  ; input a page, and arrange in into columns
  71.   PUSHF         ; save Z-flag, to see if there is more input
  72.   CALL OUTPUT_PAGE  ; process the columns-buffer into final output
  73.   CALL OFLUSH        ; flush the output buffer
  74.   POPF            ; restore Z flag, is there more output?
  75.   JNZ L1        ; loop if there is more output
  76. L2:
  77.   JMP GOOD_EXIT     ; all done, go back to operating system
  78.  
  79.  
  80. ; CHECK_DIGIT sees if there is another command-tail argument pointed to by
  81. ;   SI.  If there is, it had better start with a decimal digit, or else we
  82. ;   abort the program.    We return NZ if there is an argument; Z if there are
  83. ;   no more arguments (terminator 0FF is seen).
  84.  
  85. CHECK_DIGIT:
  86.   PUSH AX        ; preserve register across call
  87. L1:            ; loop here to skip over blanks and control chars
  88.   LODSB         ; load the next character
  89.   CMP AL,' '        ; is it a blank or control char?
  90.   JBE L1        ; loop if yes, to skip the character
  91.   DEC SI        ; retreat SI back to the first argument-char
  92.   CMP AL,0FF        ; is it the command-tail terminator?
  93.   JE >L2        ; return Z if yes
  94.   SUB AL,'0'        ; reduce first character to 0--9 range if digit
  95.   CMP AL,10        ; is the character a digit?
  96.   JAE >E1        ; abort the program if not; NZ is set if yes
  97. L2:
  98.   POP AX        ; restore clobbered register
  99.   RET
  100.  
  101. E1:            ; improper command tail in program invocation
  102.   MOV DX,DOC_MSG    ; point to the documentation-message
  103.   MOV CX,DOC_LEN    ; load size of message
  104.   JMP ERROR_EXIT    ; educate the user about this program
  105.  
  106.  
  107. ; CLEAR_PAGE calculates the number of lines to be printed on the coming
  108. ;   page, at sets up a blank columns-buffer based on that number.  We return
  109. ;   with DI pointing just beyond the blanked buffer.  If the calculations
  110. ;   indicate something is wrong, we abort the program.
  111.  
  112. CLEAR_PAGE:
  113.   MOV AL,LPAGE        ; fetch the total number of lines on a page
  114.   SUB AL,SKIPCT     ; subtract the number of lines that we skip
  115.   JBE E1        ; abort if we skip more lines than there are
  116.   SUB AL,LSTART     ; also subtract any first-page lines already output
  117.   JBE E1        ; abort if that subtraction has exhausted the count
  118.   MOV THISPAGE,AL   ; store as the number of lines on this page
  119.   MOV LSTART,0        ; cancel first-page count for the subsequent pages
  120.   MOV CX,PWIDTH     ; load the number of characters per line
  121.   MUL CL        ; calculate the number of characters in the columns buffer
  122.   XCHG CX,AX        ; swap the count into CX for blanking
  123.   MOV DI,BUF        ; point DI to the start of the columns buffer
  124.   MOV AL,' '        ; we will fill the buffer with blanks
  125.   REP STOSB        ; buffer is filled, DI points beyond the buffer
  126.   RET
  127.  
  128.  
  129. ; SCAN_ARGS scans the decimal arguments in the command tail at DS:080. All the
  130. ;   appropriate page-size variables are set according to these argument values.
  131.  
  132. SCAN_ARGS:
  133.   MOV SI,080        ; point to the command-tail buffer in the PSP
  134.   LODSB         ; load the size of the command tail
  135.   CBW            ; extend the size AL to AX
  136.   XCHG BX,AX        ; swap the size into BX, for indexing
  137.   MOV B[BX+SI],0FF  ; mark the end of the command-tail with terminator 0FF
  138.   CALL CHECK_DIGIT  ; any there any arguments in the command tail?
  139.   JZ E1         ; abort the program if there are not
  140.   CALL SCAN_DECIMAL ; input the first argument-- number of major columns
  141.   MOV NCOLS,AL        ; store it
  142.   XCHG BX,AX        ; also swap NCOLS into BL for later calculations
  143.   MOV AL,DEFT_SKIPCT; load the default number of lines skipped
  144.   CALL SCAN_DECIMAL ; read the next argument if there is any
  145.   MOV SKIPCT,AL     ; store the number of lines to skip between pages
  146.   MOV AL,DEFT_PWIDTH; load the default page width
  147.   CALL SCAN_DECIMAL ; read the next argument if there is any
  148.   MOV CL,AL        ; store in CL for the moment
  149.   DIV BL        ; divide by major columns count, to get chars per column
  150.   SUB CL,AH        ; subtract remainder from page width, insures even multiple
  151.   MOV AH,0        ; zero out the remainder
  152.   MOV WIDTH,AX        ; store the number of characters in an output column
  153.   CMP AL,2        ; this width had better be at least 2 chars
  154.   JB E1         ; abort the program if not
  155.   MOV AL,CL        ; AX is now the characters-per-line
  156.   MOV PWIDTH,AX     ; store the characters-per-line printer is set to
  157.   MOV AX,CX        ; re-fetch the characters-per-line
  158.   ADD AX,BUF        ; calculate beyond-first-line, reached when buffer full
  159.   MOV BUFEND,AX     ; store the value for later use
  160.   MOV AL,DEFT_LPAGE ; load defualt lines-per-page
  161.   CALL SCAN_DECIMAL ; read the next argument, if there is any
  162.   MOV LPAGE,AL        ; store the total number of lines on a printed page
  163.   MOV AL,DEFT_LSTART; load the default first-line-position
  164.   CALL SCAN_DECIMAL ; read the next argument, if any
  165.   MOV LSTART,AL     ; store the starting first-page position
  166.   RET
  167.  
  168.  
  169. ; GATHER_PAGE takes input text at DS:SI, and formats it into columns on a
  170. ;   single page, at BUF.  RZ if the input file end (0FFH marker) was seen.
  171.  
  172. GATHER_PAGE:
  173.   CALL CLEAR_PAGE   ; blank-fill the columns-buffer
  174.   MOV BX,DI        ; point BX beyond the columns-buffer
  175.   MOV BP,DX,DI,BUF  ; start BP=column ptr  DX=line ptr    DI=char ptr
  176. L1:            ; loop here for each column entry
  177.   CALL GATHER_LINE  ; copy an input line to a column entry
  178.   JZ RET        ; return if there is no more input
  179.   CALL NEXT_LINE    ; advance pointers to the next column entry
  180.   JB L1         ; loop if there is another entry on this page
  181.   OR AL,0FF        ; page complete: set NZ to signal more input
  182.   RET
  183.  
  184.  
  185. ; NEXT_LINE sets DI to the next line of this column in the page display buffer.
  186. ;   It moves to the top of the next column as necessary.  RAE if the page is
  187. ;   full.
  188.  
  189. NEXT_LINE:
  190.   ADD DX,PWIDTH     ; advance column-pointer to same column on the next line
  191.   CMP DX,BX        ; have we run off the end of the buffer?
  192.   JB >L1        ; skip if we have not
  193.   ADD BX,WIDTH        ; one column is complete-- advance end-buffer-limit
  194.   ADD BP,WIDTH        ; advance the column-pointer to the next column
  195.   MOV DX,BP        ; set the line-ptr to this new column
  196.   CMP BP,BUFEND     ; have the columns run off the right end of the page?
  197.   JAE RET        ; return AE if they have-- page is full of columns
  198. L1:
  199.   MOV DI,DX        ; set char-output pointer to the new line-ptr value
  200.   RET
  201.  
  202.  
  203. ; GATHER_LINE copies a line of text from SI to DI.  RZ if the input file end
  204. ;    is seen.
  205.  
  206. GATHER_LINE:
  207.   MOV CX,WIDTH        ; set up the limit for output in this column-entry
  208. L0:            ; loop here for each character output to column-entry
  209.   LODSB         ; fetch a character from the input
  210.   CMP AL,020        ; is it a control-character?
  211.   JB >L1        ; jump if yes
  212.   CMP AL,0FE        ; is it a marker?
  213.   JAE >L2        ; jump if yes
  214.   CMP AL,'_'        ; is it an underscore?
  215.   JE >L5        ; jump if yes
  216. L6:
  217.   STOSB         ; store the character in columns-buffer
  218.   LOOP L0        ; loop to look at the next character
  219.   DEC SI,2        ; column-entry has overflowed: retreat input pointer
  220.   MOV B[SI],0FE     ; mark input buffer with line-overflow marker
  221.   ES MOV B[DI-1],' '; cancel the last byte output-- it will go to next line
  222.   RET
  223.  
  224. L1:            ; control-character seen on the input line
  225.   CMP AL,0A        ; is it the line-terminator?
  226.   JNE L0        ; if not then ignore it
  227.   TEST AL,AL        ; set NZ to signal end-of-file was not seen
  228.   RET
  229.  
  230. L2:            ; a marker was seen in the input stream
  231.   JE >L4        ; jump if it was the line-overflow marker
  232.   CALL READ_SOURCE  ; it was the end-of-file marker: read more input
  233.   JNE L0        ; loop for more reading if there was more input
  234.   RET            ; input exhausted-- return Z to caller
  235.  
  236. L4:            ; a line-overflow marker was seen in the input-stream
  237.   PUSH BX,CX,DI     ; preserve registers across indentation
  238.   MOV AL,0A        ; we will look for the linefeed for this line
  239.   MOV DI,SI        ; transfer source pointer to DI for linefeed-search
  240.   REPNE SCASB        ; find where the linefeed is
  241.   CMP B[DI-2],0D    ; was there also a carriage return?
  242.   IF E INC CX       ; if yes then don't count it
  243.   MOV BX,CX        ; preserve the count for reducing the stacked CX value
  244.   POP DI        ; restore columnar-output pointer
  245.   MOV AL,' '        ; load blank-- we are indenting to right-justify overflow
  246.   REP STOSB        ; now the overflow is indented
  247.   POP CX        ; restore original count
  248.   SUB CX,BX        ; reduce count by the number of blanks we indented
  249.   POP BX        ; restore clobbered register
  250.   JMP L0
  251.  
  252. L5:            ; an underscore was seen in the input stream
  253.   CMP LPAGE,80        ; are we squeezing those lines tightly on a page?
  254.   JBE L6        ; jump if not, no need to convert
  255.   MOV AL,'-'        ; tight squeeze: change to hyphen for readability
  256.   JMP L6        ; re-join the main storage-loop
  257.  
  258.  
  259. ; SCAN_DECIMAL sets AX to the value of the next decimal-number argument
  260. ;   pointed to by SI, and advances SI beyond the argument.  If there are
  261. ;   no more arguments, we retain the input value AL as our return-value.
  262.  
  263. SCAN_DECIMAL:
  264.   MOV AH,0        ; high-byte of default value is always zero
  265.   CALL CHECK_DIGIT  ; is there an argument there?
  266.   JZ RET        ; return the default value if there was not
  267.   PUSH BX,DX        ; preserve registers across call
  268.   SUB BX,BX        ; initialize BX, we will accumulate value there
  269. L1:            ; loop here for each digit of the number
  270.   LODSB         ; load the next digit
  271.   SUB AL,'0'        ; reduce the digit to a binary value
  272.   MOV DX,10        ; load multiplicand, it is also the digit-limit value
  273.   CMP AL,DL        ; is it in fact another decimal digit?
  274.   JAE >L2        ; jump if not to exit this procedure
  275.   CBW            ; extend value AL to AX
  276.   XCHG AX,BX        ; swap previous accumulation into AX, new digit into BX
  277.   MUL DX        ; multiply the previous accumulation by 10
  278.   ADD BX,AX        ; add into the new digit value
  279.   JMP L1        ; loop to accumulate another digit
  280.  
  281. L2:            ; non-digit was seen
  282.   DEC SI        ; retreat back to the non-digit
  283.   XCHG AX,BX        ; swap the accumulated value into AX
  284.   POP DX,BX        ; restore clobbered registers
  285.   RET
  286.  
  287.  
  288. ; OUTPUT_PAGE transforms the column-buffer output into final-form output,
  289. ;   with CRLFs inserted and trailing blanks removed.
  290.  
  291. OUTPUT_PAGE:
  292.   PUSH CX,DX,SI     ; preserve registers across call
  293.   MOV DI,OUTBUF     ; initialize the output pointer
  294.   MOV DX,PWIDTH     ; DX holds the count of each columnized line
  295.   MOV SI,BUF        ; initialize the column-buffer source pointer
  296.   MOV CL,THISPAGE   ; load the lines count into CL
  297.   MOV CH,0        ; extend the CL-count to CX
  298. L1:            ; loop here to output each line
  299.   CALL OUTPUT_LINE  ; output the line
  300.   ADD SI,DX        ; advance the source pointer to the next columnized line
  301.   LOOP L1        ; loop to output the next line
  302.   POP SI,DX,CX        ; restore clobbered registers
  303.   MOV AH,SKIPCT     ; load the count of lines to skip
  304.   TEST AH,AH        ; are there any lines to skip?
  305.   JZ RET        ; return if not
  306. L2:            ; loop here for each skipped line between pages
  307.   CALL CRLF_OUT     ; output a blank line
  308.   DEC AH        ; count down lines
  309.   JNZ L2        ; loop to output the next blank line
  310.   RET
  311.  
  312.  
  313. ; OUTPUT_LINE transforms a single line of columnized output into its final
  314. ;   form, with trailing blanks removed and a CRLF appended to the end of the
  315. ;   line.
  316.  
  317. OUTPUT_LINE:
  318.   PUSH CX,SI        ; preserve registers across call
  319.   MOV CX,DX        ; fetch the count of columnized-line bytes
  320.   PUSH DI        ; preserve the output pointer
  321.   MOV DI,SI        ; load DI with source pointer, for scanning
  322.   ADD DI,CX        ; advance DI beyond this source line
  323.   DEC DI        ; retreat to the last byte of this source line
  324.   MOV AL,' '        ; load blank, to scan for trailing blanks
  325.   STD            ; scanning will be backwards
  326.   REPE SCASB        ; scan through the trailing blanks
  327.   CLD            ; restore forward scanning
  328.   IF NE INC CX        ; do not include the last byte if it was a non-blank
  329.   POP DI        ; restore output pointer
  330.   REP MOVSB        ; CX was decremented by # of trailing blanks; now move line
  331.   POP SI,CX        ; restore clobbered registers
  332. CRLF_OUT:        ; output a CRLF to the end of a line
  333.   PUSH AX        ; preserve AX across call
  334.   MOV AX,0A0D        ; load CRLF, backwards according to 8086 storage conventions
  335.   STOSW         ; output the CRLF
  336.   POP AX        ; restore clobbered register
  337. CHECK_FLUSH:        ; check to see if we need to flush the output buffer
  338.   CMP DI,OUTBUF_LIM ; have we reached the buffer limit?
  339.   JB RET        ; do nothing if we have not reached the limit
  340. OFLUSH:         ; flush the output buffer
  341.   PUSH AX,BX,CX,DX  ; save registers across call
  342.   MOV BX,1        ; handle-number for standard output is 1
  343.   MOV DX,OUTBUF     ; point DX to the output buffer
  344.   MOV CX,DI        ; point CX beyond the bytes we have output
  345.   SUB CX,DX        ; calculate the number of bytes output
  346.   CALL MWRITE        ; send those bytes to standard output
  347.   MOV DI,DX        ; reset the output-pointer to the start of the buffer
  348.   POP DX,CX,BX,AX   ; restore clobbered registers
  349.   RET
  350.  
  351.  
  352. ; READ_SOURCE reads from standard input to SOURCE_BUF, and marks the end
  353. ;    of the received text with 0FF.  Return with SI pointing to SOURCE_BUF.
  354. ;    RZ if there was no more input.
  355.  
  356. READ_SOURCE:
  357.   PUSH AX,BX,CX,DX  ; preserve registers across call
  358.   SUB BX,BX        ; handle-value for standard input is zero
  359.   MOV DX,SOURCE_BUF ; point to the destination for our source-read
  360.   MOV CX,04000        ; load the size limit for the read
  361.   CALL MREAD        ; read from standard input into the source buffer
  362.   XCHG BX,AX        ; swap the actual number of bytes read into BX
  363.   MOV SI,DX        ; point SI to the bytes that were read
  364.   MOV B[BX+SI],0FF  ; terminate the bytes with an 0FF marker
  365.   TEST BX,BX        ; set Z if there were no bytes read
  366.   POP DX,CX,BX,AX   ; restore clobbered registers
  367.   RET
  368.  
  369.  
  370. ; MREAD reads from the open-file numbered BX, to the CX bytes at DX.  Return
  371. ;   with AX set to the number of bytes actually read.
  372.  
  373. MREAD:
  374.   MOV AH,03FH        ; MSDOS function number for READ
  375. MSDOS:
  376.   INT 021H        ; all MSDOS calls go through this interrupt
  377.   RET
  378.  
  379.  
  380. ; MWRITE writes SI bytes from CX to the open-file numbered BX.    Return Carry if
  381. ;   the write failed, with AX set to an error number.
  382.  
  383. MWRITE:
  384.   MOV AH,040H        ; MSDOS function number for WRITE
  385.   JMP MSDOS        ; jump to call the operating system
  386.  
  387.  
  388. ; EXIT exits the program back to the invoking process, with a status of AL.
  389.  
  390. GOOD_EXIT:
  391.   MOV AL,0        ; zero status means success
  392. EXIT:
  393.   MOV AH,04CH        ; MSDOS function number for EXIT
  394.   JMP MSDOS        ; jump to call the operating system
  395.  
  396.  
  397. ; ERROR_EXIT writes to the error-console the message of CX bytes at DS:DX;
  398. ;   then exits the program with a status of 1.
  399.  
  400. ERROR_EXIT:
  401.   MOV BX,2        ; handle-value for error-console is 2
  402.   CALL MWRITE        ; write message to the error-console
  403.   MOV AL,1        ; 1-code means failure
  404.   JMP EXIT        ; go back to operating system
  405.